package com.wideplay.warp.clustering.oscache;

import com.wideplay.warp.clustering.DataGrid;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Injector;
import com.google.inject.Inject;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
import com.opensymphony.oscache.base.NeedsRefreshException;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created with IntelliJ IDEA.
 * On: 23/06/2007
 *
 * @author Dhanji R. Prasanna
 * @since 1.0
 */
class OsCacheDataGridImpl implements DataGrid {
    private GeneralCacheAdministrator admin;
    private final Lock lock = new ReentrantLock();

    private final Injector injector;

    @Inject
    public OsCacheDataGridImpl(Injector injector) {
        this.injector = injector;
    }

    void setAdmin(GeneralCacheAdministrator admin) {
        this.admin = admin;
    }

    public <T> void descope(Key<T> key) {
        lock.lock();
        try {
            final String keyString = key.toString();
            admin.removeEntry(keyString);
            admin.flushEntry(keyString);
        } finally {
            lock.unlock();
        }
    }


    public void flush() {
        lock.lock();
        try {
            admin.flushAll();
        } finally {
            lock.unlock();
        }
    }

    public <T> void flush(Key<T> key) {
        lock.lock();
        try {
            String keyString = key.toString();
            admin.putInCache(keyString, injector.getInstance(key));
            admin.flushEntry(keyString);
        } finally {
            lock.unlock();
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T get(String key, Provider<T> creator) {
        T object;
        lock.lock();
        try {
            object = (T) admin.getFromCache(key, 1000);
            
        } catch (NeedsRefreshException e) {
            object = creator.get();
            admin.putInCache(key, object);
            admin.flushEntry(key);
        } finally {
            lock.unlock();
        }

        return object;
    }
}
